package com.zjhn.ds.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.zjhn.ds.common.BizResult;
import com.zjhn.ds.common.exception.BizException;
import com.zjhn.ds.domain.dto.mt.AddStationDto;
import com.zjhn.ds.domain.dto.mt.DetailStationDto;
import com.zjhn.ds.domain.dto.mt.GetProduceAndWarnDto;
import com.zjhn.ds.domain.dto.mt.NeedProduceDetailDto;
import com.zjhn.ds.domain.dto.mt.NeedProduceDto;
import com.zjhn.ds.domain.dto.mt.ProTaskDetailDto;
import com.zjhn.ds.domain.dto.mt.ProTaskDto;
import com.zjhn.ds.domain.entity.erp.Customer;
import com.zjhn.ds.domain.entity.erp.ProTask;
import com.zjhn.ds.domain.entity.erp.ProTaskDetail;
import com.zjhn.ds.domain.entity.erp.TradeOrder;
import com.zjhn.ds.domain.entity.erp.TradeOrderDetail;
import com.zjhn.ds.domain.entity.jlw.AssignTask;
import com.zjhn.ds.domain.entity.jlw.Station;
import com.zjhn.ds.domain.entity.jlw.SwipeCardInfo;
import com.zjhn.ds.domain.entity.jlw.WorkshopClasses;
import com.zjhn.ds.domain.vo.TradeOrderCodeVo;
import com.zjhn.ds.mapper.CustomerMapper;
import com.zjhn.ds.mapper.ProTaskDetailMapper;
import com.zjhn.ds.mapper.ProTaskMapper;
import com.zjhn.ds.mapper.StationMapper;
import com.zjhn.ds.mapper.SwipeCardInfoMapper;
import com.zjhn.ds.mapper.TradeOrderDetailMapper;
import com.zjhn.ds.mapper.TradeOrderMapper;
import com.zjhn.ds.mapper.WorkshopClassesMapper;
import com.zjhn.ds.param.AssignTaskBatchParam;
import com.zjhn.ds.param.AssignTaskParam;
import com.zjhn.ds.param.GetProTaskParam;
import com.zjhn.ds.param.GetStationListParam;
import com.zjhn.ds.param.SetProduceAndWarnParam;
import com.zjhn.ds.service.AssignTaskService;
import com.zjhn.ds.service.ProTaskService;
import com.zjhn.ds.utils.CommonUtil;
import com.zjhn.ds.utils.base.CustomUtil;
import com.zjhn.ds.utils.base.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @BelongsProject: ds_jlw
 * @BelongsPackage: com.zjhn.ds.service.impl
 * @Author: sxt
 * @CreateTime: 2023-09-23  13:42
 * @Description:
 * @Version: 1.0
 */
@Slf4j
@Service
public class ProTaskServiceImpl implements ProTaskService {

    @Resource
    private CommonUtil commonUtil;

    @Resource
    private ProTaskMapper proTaskMapper;

    @Resource
    private ProTaskDetailMapper proTaskDetailMapper;

    @Resource
    private TradeOrderMapper tradeOrderMapper;

    @Resource
    private TradeOrderDetailMapper tradeOrderDetailMapper;

    @Resource
    private CustomerMapper customerMapper;

    @Resource
    private AssignTaskService assignTaskService;

    @Resource
    private WorkshopClassesMapper workshopClassesMapper;

    @Resource
    private StationMapper stationMapper;

    @Resource
    private SwipeCardInfoMapper swipeCardInfoMapper;


    /**
     * 获取生产单信息
     *
     * @param param
     * @return
     */
    @Override
    public BizResult<List<ProTaskDto>> getProTaskList(GetProTaskParam param) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime oneYearAgo = now.minusMonths(1);
        Date start = Date.from(oneYearAgo.atZone(ZoneId.systemDefault()).toInstant());
        Date end = new Date();
        if (StringUtils.isNotBlank(param.getStartDate()))
            start = DateUtil.formatStringToDate(param.getStartDate(), DateUtil.DEFAULT_DATE_FORMAT);
        if (StringUtils.isNotBlank(param.getEndDate()))
            end = DateUtil.formatStringToDate(param.getEndDate(), DateUtil.DEFAULT_DATE_FORMAT);

        MPJLambdaWrapper<ProTask> queryWrapper = new MPJLambdaWrapper<>();
        queryWrapper
                .selectAll(ProTask.class)
                .innerJoin(TradeOrder.class, "o", TradeOrder::getId, ProTask::getTradeOrderId)
                .innerJoin(Customer.class, "c", Customer::getId, TradeOrder::getCustomerId)
                .eq("t.IsDeleted", 0).eq("t.is_finish", param.getIsOver());
        if (param.getIsOver() == 1)
            queryWrapper.between("t.CreationTime", start, end);

        if (StringUtils.isNotBlank(param.getSearch()))
            queryWrapper.and(
                    c -> c.like("t.khStyle", param.getSearch())
                            .or()
                            .like("c.name", param.getSearch())
                            .or()
                            .like("t.code", param.getSearch())
            );
        List<ProTask> proTasks = proTaskMapper
                .selectJoinList(ProTask.class, queryWrapper.orderByAsc("t.CreationTime"));

        List<ProTaskDto> res = new ArrayList<>();
        if (!proTasks.isEmpty()) {
            // trade_order
            List<String> tradeOrderIds = proTasks.stream().map(ProTask::getTradeOrderId).collect(Collectors.toList());
            List<TradeOrder> tradeOrders = tradeOrderMapper.selectBatchIds(tradeOrderIds);
            if (tradeOrders.isEmpty())
                throw new BizException("订单不存在");
            Map<String, TradeOrder> tradeOrderMap = tradeOrders.stream().collect(Collectors.toMap(TradeOrder::getId, c -> c));

            // trade_order_detail
            List<TradeOrderDetail> tradeOrderDetails = tradeOrderDetailMapper.selectList(
                    new QueryWrapper<TradeOrderDetail>()
                            .in("order_id", tradeOrderIds)
                            .eq("IsDeleted", 0));
            Map<String, String> orderCodeMap = new HashMap<>();
            if (!tradeOrderDetails.isEmpty()) {
                Map<String, List<TradeOrderDetail>> detailMap = tradeOrderDetails.stream().collect(Collectors.groupingBy(TradeOrderDetail::getOrderId));
                orderCodeMap = detailMap.entrySet().stream().map(c ->
                        TradeOrderCodeVo.builder()
                                .tradeOrderId(c.getKey())
                                .styleCode(String.join(",", c.getValue().stream()
                                        .map(TradeOrderDetail::getStyleCode)
                                        .collect(Collectors.toSet())))
                                .build()
                ).collect(Collectors.toMap(TradeOrderCodeVo::getTradeOrderId, TradeOrderCodeVo::getStyleCode));
            }

            // BasicCustomer
            List<String> customerIds = tradeOrders.stream().map(TradeOrder::getCustomerId).collect(Collectors.toList());
            Map<String, String> customerNameMap = new HashMap<>();
            if (!customerIds.isEmpty()) {
                List<Customer> customers = customerMapper.selectBatchIds(customerIds);
                if (!customers.isEmpty())
                    customerNameMap = customers.stream().collect(Collectors.toMap(Customer::getId, Customer::getName));
            }

            // 派工单
            List<String> proTaskIds = proTasks.stream().map(ProTask::getId).collect(Collectors.toList());
            List<AssignTask> assignTasks = assignTaskService.list(new QueryWrapper<AssignTask>()
                    .in("task_id", proTaskIds));
            Map<String, List<AssignTask>> assignTaskMap = new HashMap<>();
            if (!assignTasks.isEmpty()) {
                assignTaskMap = assignTasks.stream().collect(Collectors.groupingBy(AssignTask::getTaskId));
            }

            Map<String, List<ProTaskDetail>> proTaskDetailMap = new HashMap<>();
            List<ProTaskDetail> proTaskDetails = proTaskDetailMapper.selectList(
                    new QueryWrapper<ProTaskDetail>()
                            .in("task_id", proTaskIds)
                            .eq("type", 0));
            if (!proTaskDetails.isEmpty())
                proTaskDetailMap.putAll(proTaskDetails.stream().collect(Collectors.groupingBy(ProTaskDetail::getTaskId)));

            for (ProTask proTask : proTasks) {
                List<ProTaskDetail> details = proTaskDetailMap.get(proTask.getId());
                if (details == null)
                    continue;

                ProTaskDto build = ProTaskDto.builder()
                        .proTaskId(proTask.getId())
                        .proTaskCode(proTask.getCode())
                        .styleCode(orderCodeMap.get(proTask.getTradeOrderId()))
                        .planQty(String.valueOf(proTask.getNumber()))
                        .produceQty("0")
                        .taskTime(DateUtil.formatDateToString(proTask.getCreationTime(), DateUtil.DATE_FORMAT_1))
                        // 交期 改成 生产交期
                        .orderHod(DateUtil.formatDateToString(details.get(0).getOrderHod(), DateUtil.DATE_FORMAT_1))
                        .overDue(false)
                        .build();
                TradeOrder tradeOrder = tradeOrderMap.get(proTask.getTradeOrderId());
                if (tradeOrder != null) {
                    // tradeOrderCode  customer  orderTime  deliveryDate
                    build.setTradeOrderCode(tradeOrder.getCode());
                    build.setCustomer(customerNameMap.get(tradeOrder.getCustomerId()));
                    build.setOrderTime(DateUtil.formatDateToString(tradeOrder.getCreationTime(), DateUtil.DATE_FORMAT_1));
                    build.setDeliveryDate(
                            tradeOrder.getHod1() == null ?
                                    null : DateUtil.formatDateToString(tradeOrder.getHod1(), DateUtil.DATE_FORMAT_1)
                    );
                    build.setKhStyle(tradeOrder.getKhStyle());
                    if (tradeOrder.getHod1().compareTo(new Date()) < 1)
                        build.setOverDue(true);
                }
                // produceQty 产量计算
                List<AssignTask> tasks = assignTaskMap.get(proTask.getId());
                if (tasks != null && !tasks.isEmpty())
                    build.setProduceQty(
                            tasks.stream()
                                    .map(AssignTask::getCompleteQty)
                                    .reduce(BigDecimal.ZERO, BigDecimal::add)
                                    .toString());

                res.add(build);
            }
        }

        return BizResult.success(res);
    }

    /**
     * 获取生产单明细
     *
     * @param proTaskId
     * @return
     */
    @Override
    public BizResult<List<ProTaskDetailDto>> getProTaskDetails(String proTaskId, String styleCode) {
        List<ProTaskDetailDto> res = new ArrayList<>();
        List<ProTaskDetail> proTaskDetails = proTaskDetailMapper.selectList(
                new QueryWrapper<ProTaskDetail>().eq("type", 0).eq("task_id", proTaskId).eq("IsDeleted", 0));
        if (proTaskDetails.size() > 0) {
            // trade_order_detail
            List<String> orderDetailIds = proTaskDetails.stream().map(ProTaskDetail::getTradeOrderDetailId).collect(Collectors.toList());
            List<TradeOrderDetail> tradeOrderDetails = tradeOrderDetailMapper.selectBatchIds(orderDetailIds);
            Map<String, TradeOrderDetail> orderDetailMap = tradeOrderDetails.stream().collect(Collectors.toMap(TradeOrderDetail::getId, c -> c));

            // 获取所有明细的派工单 待加工/已完成
            List<String> detailIds = proTaskDetails.stream().map(ProTaskDetail::getId).collect(Collectors.toList());
            List<AssignTask> list = assignTaskService.list(
                    new QueryWrapper<AssignTask>()
                            .in("task_detail_id", detailIds));
            Map<String, List<AssignTask>> assignTaskMap = new HashMap<>();
            if (list.size() > 0)
                assignTaskMap = list.stream().collect(Collectors.groupingBy(AssignTask::getTaskDetailId));

            for (ProTaskDetail proTaskDetail : proTaskDetails) {
                ProTaskDetailDto build = ProTaskDetailDto.builder()
                        .proTaskDetailId(proTaskDetail.getId())
                        .orderHod(
                                proTaskDetail.getOrderHod() == null ?
                                        null :
                                        DateUtil.formatDateToString(proTaskDetail.getOrderHod(), DateUtil.DATE_FORMAT_1))
                        .detailQty(BigDecimal.valueOf(proTaskDetail.getNumber()))
                        .detailFinishQty(BigDecimal.ZERO)
                        .detailAssignQty(BigDecimal.ZERO)
                        .build();

                TradeOrderDetail tradeOrderDetail = orderDetailMap.get(proTaskDetail.getTradeOrderDetailId());
                if (tradeOrderDetail != null) {
                    build.setStyleCode(tradeOrderDetail.getStyleCode());
                    build.setColor(tradeOrderDetail.getColor());
                    build.setNeedle(tradeOrderDetail.getNeedle());
                    build.setColorMain(tradeOrderDetail.getColorMain());
                    build.setSize(tradeOrderDetail.getSize());
                }
                if (StringUtils.isNotBlank(styleCode))
                    if (!build.getStyleCode().contains(styleCode))
                        continue;

                List<AssignTask> assignTasks = assignTaskMap.get(proTaskDetail.getId());
                if (assignTasks != null && assignTasks.size() > 0) {
                    build.setDetailAssignQty(assignTasks.stream().map(AssignTask::getAssignQty).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
                    build.setDetailFinishQty(assignTasks.stream().map(AssignTask::getCompleteQty).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
                }
                res.add(build);
            }
        }

        if (res.size() > 0) {
            res.sort(
                    Comparator.comparing(ProTaskDetailDto::getStyleCode)
                            .thenComparing(ProTaskDetailDto::getSize)
                            .thenComparing(ProTaskDetailDto::getColorMain)
            );
        }

        return BizResult.success(res);
    }

    /**
     * 设置明细班次产量和预警值
     *
     * @param param
     * @return
     */
    @Transactional
    @Override
    public BizResult<?> setProduceAndWarn(SetProduceAndWarnParam param) {
        ProTaskDetail proTaskDetail = proTaskDetailMapper.selectById(param.getProTaskDetailId());
        if (proTaskDetail == null)
            return BizResult.fail("生产明细不存在");

        if (param.getType() == 1) {
            // 班次产量
            proTaskDetail.setProduceQty(param.getValue());

            // 修改明细派工耗时 进行中
            List<AssignTask> list = assignTaskService.list(
                    new QueryWrapper<AssignTask>()
                            .eq("task_detail_id", param.getProTaskDetailId()).eq("task_status", 1));

            // 获取车间班次
            Integer count = workshopClassesMapper.selectCount(new QueryWrapper<WorkshopClasses>().eq("workshop_id", param.getWorkshopId()));
            if (count > 0 && param.getValue().compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal classTime = BigDecimal.valueOf(24).divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP);
                for (AssignTask assignTask : list) {
                    // 计算机台派工耗时
                    BigDecimal timeSpend = BigDecimal.ZERO;
                    if (assignTask.getAssignQty().compareTo(BigDecimal.ZERO) > 0)
                        timeSpend = assignTask.getAssignQty()
                                // 计算成分钟
                                .multiply(classTime)
                                .multiply(BigDecimal.valueOf(60)
                                        .divide(param.getValue(), 0, RoundingMode.HALF_UP));
                    assignTask.setRequire(timeSpend.intValue());
                }
            } else list.forEach(c -> c.setRequire(0));

            assignTaskService.updateBatchById(list);
        } else {
            // 预警值
            proTaskDetail.setWarnQty(param.getValue());
        }
        proTaskDetailMapper.updateById(proTaskDetail);
        return BizResult.success();
    }

    /**
     * 获取明细班次产量和预警值
     *
     * @param proTaskDetailId
     * @return
     */
    @Override
    public BizResult<GetProduceAndWarnDto> getProduceAndWarn(String proTaskDetailId, String workshopId) {
        ProTaskDetail proTaskDetail = proTaskDetailMapper.selectById(proTaskDetailId);
        if (proTaskDetail == null)
            return BizResult.fail("生产明细不存在");

        if (proTaskDetail.getWarnQty() == null) {
            proTaskDetail.setWarnQty(BigDecimal.valueOf(proTaskDetail.getNumber() * 0.8));
            proTaskDetailMapper.updateById(proTaskDetail);
        }

        Integer count = workshopClassesMapper.selectCount(new QueryWrapper<WorkshopClasses>().eq("workshop_id", workshopId));
        return BizResult.success(GetProduceAndWarnDto.builder()
                .produceQty(proTaskDetail.getProduceQty())
                .warnQty(proTaskDetail.getWarnQty())
                .classQty(count)
                .build());
    }

    /**
     * 添加工位 获取车间机台信息
     *
     * @param param
     * @return
     */
    @Override
    public BizResult<List<AddStationDto>> getStationList(GetStationListParam param) {
        List<AddStationDto> res = new ArrayList<>();

        List<Station> stations = stationMapper.selectList(
                new QueryWrapper<Station>()
                        .eq("workshop_id", param.getWorkshopId())
                        .orderByAsc("line_number", "column_number", "station_code"));
        if (stations.size() > 0) {
            List<String> stationIds = stations.stream().map(Station::getId).collect(Collectors.toList());
            // 计算时间 待加工/进行中
            List<AssignTask> assignTasks = assignTaskService
                    .list(new QueryWrapper<AssignTask>().in("station_id", stationIds));

            // 工位剔除 待加工/进行中/已完成 任务
            List<AssignTask> list = assignTaskService
                    .list(new QueryWrapper<AssignTask>().in("task_detail_id", param.getProTaskDetailId()));

            for (Station station : stations) {
                String needleNumber = commonUtil.getEquipmentById(commonUtil.getBindInfoById(station.getId())).getNeedleNumber();
                if (StringUtils.isNotBlank(param.getNeedle()) && !param.getNeedle().equals(needleNumber))
                    continue;
                if (list.size() > 0) {
                    // 剔除已派工工位
                    List<String> collect = list.stream().map(AssignTask::getStationId).collect(Collectors.toList());
                    if (collect.contains(station.getId()))
                        continue;
                }

                AddStationDto build = AddStationDto.builder()
                        .stationId(station.getId())
                        .stationName(station.getStationName())
                        .stationCode(station.getStationCode())
                        .needle(needleNumber)
                        .taskQty(0)
                        .finishTime("--")
                        .build();

                if (StringUtils.isNotBlank(param.getStationCode()))
                    if (!build.getStationCode().contains(param.getStationCode()))
                        continue;

                if (assignTasks.size() > 0) {
                    List<AssignTask> assignTaskList = assignTasks.stream()
                            .filter(c -> c.getStationId().equals(station.getId()) && c.getTaskStatus() == 1).collect(Collectors.toList());

                    if (assignTaskList.size() > 0) {
                        Date finishTime = CustomUtil.calculateFinishTime(assignTaskList);

                        build.setTaskQty(assignTaskList.size());
                        build.setFinishTime(DateUtil.formatDateToString(finishTime, DateUtil.DATE_FORMAT_1));
                    }
                }

                res.add(build);
            }
        }

        // 排序
        res.sort((o1, o2) -> {
            String[] parts1 = o1.getStationCode().split("-");
            String[] parts2 = o2.getStationCode().split("-");

            int num1 = Integer.parseInt(parts1[0].substring(1) + parts1[1] + parts1[2]);
            int num2 = Integer.parseInt(parts2[0].substring(1) + parts2[1] + parts2[2]);

            return Integer.compare(num1, num2);
        });

        return BizResult.success(res);
    }


    /**
     * 获取明细已派工工位信息
     *
     * @param proTaskDetailId
     * @return
     */
    @Override
    public BizResult<List<DetailStationDto>> detailStation(String proTaskDetailId) {
        // 明细下的所有派工任务 进行中/已完成
        List<AssignTask> assignTasks = assignTaskService
                .list(new QueryWrapper<AssignTask>().in("task_detail_id", proTaskDetailId));

        List<DetailStationDto> res = new ArrayList<>();
        if (assignTasks.size() > 0) {
            for (AssignTask assignTask : assignTasks) {
                DetailStationDto build = DetailStationDto.builder()
                        .assignTaskId(assignTask.getId())
                        .stationId(assignTask.getStationId())
                        .stationName(commonUtil.getStationById(assignTask.getStationId()).getStationName())
                        .stationCode(commonUtil.getStationById(assignTask.getStationId()).getStationCode())
                        .produceTime(0)
                        .completeQty(assignTask.getCompleteQty())
                        .assignQty(assignTask.getAssignQty())
                        .status(commonUtil.getStationStatus(assignTask.getStationId()))
                        .taskStatus(assignTask.getTaskStatus())
                        .build();
                if (assignTask.getTaskStatus() != 3 && assignTask.getRequire() > 0)
                    // 计算生产时间
                    build.setProduceTime(
                            BigDecimal.valueOf(assignTask.getRequire())
                                    .divide(BigDecimal.valueOf(60 * 24), 0, RoundingMode.HALF_UP)
                                    .intValue());
                res.add(build);
            }
            // 排序
            res.sort((o1, o2) -> {
                String[] parts1 = o1.getStationCode().split("-");
                String[] parts2 = o2.getStationCode().split("-");

                int num1 = Integer.parseInt(parts1[0].substring(1) + parts1[1] + parts1[2]);
                int num2 = Integer.parseInt(parts2[0].substring(1) + parts2[1] + parts2[2]);

                return Integer.compare(num1, num2);
            });
        }

        return BizResult.success(res);
    }

    /**
     * 明细工位派工任务删除
     *
     * @param assignTaskId
     * @return
     */
    @Transactional
    @Override
    public BizResult<?> removeAssignTask(String assignTaskId) {
        AssignTask assignTask = assignTaskService.getById(assignTaskId);
        if (assignTask == null)
            return BizResult.fail("派工任务不存在");
        if (assignTask.getCompleteQty().compareTo(BigDecimal.ZERO) > 0)
            return BizResult.fail("当前工位任务已进行报工，无法删除");

        assignTaskService.removeById(assignTaskId);
        swipeCardInfoMapper.delete(new QueryWrapper<SwipeCardInfo>().eq("assign_task_id", assignTaskId));
        return BizResult.success();
    }

    /**
     * 批量派工
     *
     * @param param
     * @return
     */
    @Override
    public BizResult<?> assignTaskBatch(AssignTaskParam param) {
        ProTaskDetail proTaskDetail = proTaskDetailMapper.selectById(param.getProTaskDetailId());
        if (proTaskDetail == null)
            return BizResult.fail("生产明细不存在");
        Integer classTime = workshopClassesMapper.selectCount(new QueryWrapper<WorkshopClasses>().eq("workshop_id", param.getWorkshopId()));

        List<AssignTask> assignTasks = new ArrayList<>();
        for (AssignTaskBatchParam task : param.getTasks()) {
            AssignTask assignTask = AssignTask.builder()
                    .taskId(proTaskDetail.getTaskId())
                    .taskDetailId(proTaskDetail.getId())
                    .stationId(task.getStationId())
                    .taskStatus(1)
                    .assignQty(task.getAssignQty())
                    .completeQty(BigDecimal.ZERO)
                    .beginTime(new Date())
                    .completeTime(null)
                    .require(0)
                    .build();

            if (classTime != 0 && proTaskDetail.getProduceQty() != null && proTaskDetail.getProduceQty().compareTo(BigDecimal.ZERO) == 0)
                assignTask.setRequire(assignTask.getAssignQty()
                        .multiply(BigDecimal.valueOf(24 * 60))
                        .divide(proTaskDetail.getProduceQty()
                                .multiply(BigDecimal.valueOf(classTime)), 0, RoundingMode.HALF_UP)
                        .intValue());
            assignTasks.add(assignTask);
        }
        assignTaskService.saveOrUpdateBatch(assignTasks);
        return BizResult.success();
    }

    /**
     * 生产单任务结束
     *
     * @param proTaskId
     * @return
     */
    @Transactional
    @Override
    public BizResult<?> proTaskFinish(String proTaskId) {
        ProTask proTask = proTaskMapper.selectById(proTaskId);
        if (proTask == null || proTask.getIsDeleted() == 1)
            return BizResult.fail("生产单任务不存在");

        List<ProTaskDetail> proTaskDetails = proTaskDetailMapper.selectList(
                new QueryWrapper<ProTaskDetail>()
                        .eq("task_id", proTaskId)
                        .eq("IsDeleted", 0));
        if (proTaskDetails.size() > 0) {
            // 删除刷卡信息
            List<String> proTaskDetailId = proTaskDetails.stream().map(ProTaskDetail::getId).collect(Collectors.toList());
            swipeCardInfoMapper.delete(new QueryWrapper<SwipeCardInfo>().in("pro_task_detail_id", proTaskDetailId));
        }

        assignTaskService.update(
                new UpdateWrapper<AssignTask>()
                        .eq("task_id", proTaskId)
                        .set("task_status", 2)
                        .set("complete_time", new Date())
        );

        proTask.setIsFinish(1);
        proTaskMapper.updateById(proTask);

        return BizResult.success();
    }

    /**
     * 生产单任务激活
     *
     * @param proTaskId
     * @return
     */
    @Override
    public BizResult<?> proTaskActive(String proTaskId) {
        ProTask proTask = proTaskMapper.selectById(proTaskId);
        if (proTask == null || proTask.getIsDeleted() == 1)
            return BizResult.fail("生产单任务不存在");
        proTask.setIsFinish(0);
        proTaskMapper.updateById(proTask);

        return BizResult.success();
    }

    /**
     * 获取待生产统计表信息
     * @return
     */
    @Override
    public BizResult<List<NeedProduceDto>> getNeedProduceList() {
        List<ProTask> proTaskList = proTaskMapper.selectList(new QueryWrapper<ProTask>().eq("IsDeleted", 0));
        Map<String, List<ProTaskDetail>> proTaskDetailMap = new HashMap<>();
        if (!proTaskList.isEmpty()) {
            List<ProTaskDetail> details = proTaskDetailMapper
                    .selectList(new QueryWrapper<ProTaskDetail>().eq("type", 0));

            if (!details.isEmpty())
                proTaskDetailMap.putAll(details.stream().collect(Collectors.groupingBy(ProTaskDetail::getTaskId)));
        }

        // 生产单未完成并且是非委外的订单明细
        List<ProTaskDetail> proTaskDetails = new ArrayList<>();
        for (ProTask proTask : proTaskList) {
            List<ProTaskDetail> details = proTaskDetailMap.get(proTask.getId());
            if (details != null && !details.isEmpty())
                if (proTask.getIsFinish() == 0)
                    proTaskDetails.addAll(details);
        }

        Map<String, List<AssignTask>> assignTaskMap = new HashMap<>();
        Map<String, TradeOrderDetail> tradeOrderDetailMap = new HashMap<>();
        if (!proTaskDetails.isEmpty()) {
            Set<String> tradeOrderDetailIds = proTaskDetails.stream().map(ProTaskDetail::getTradeOrderDetailId).collect(Collectors.toSet());
            if (!tradeOrderDetailIds.isEmpty()) {
                List<TradeOrderDetail> tradeOrderDetail = tradeOrderDetailMapper.selectBatchIds(tradeOrderDetailIds);
                if (!tradeOrderDetail.isEmpty())
                    tradeOrderDetailMap.putAll(tradeOrderDetail.stream().collect(Collectors.toMap(TradeOrderDetail::getId, c -> c)));
            }

            List<String> proTaskDetailIds = proTaskDetails.stream().map(ProTaskDetail::getId).collect(Collectors.toList());
            List<AssignTask> assignTasks = assignTaskService.list(new QueryWrapper<AssignTask>()
                    .in("task_detail_id", proTaskDetailIds));
            if (!assignTasks.isEmpty())
                assignTaskMap.putAll(assignTasks.stream().collect(Collectors.groupingBy(AssignTask::getTaskDetailId)));
        }

        List<NeedProduceDto> res = new ArrayList<>();
        for (ProTaskDetail proTaskDetail : proTaskDetails) {
            TradeOrderDetail tradeOrderDetail = tradeOrderDetailMap.get(proTaskDetail.getTradeOrderDetailId());
            if (tradeOrderDetail == null)
                continue;
            String needle = tradeOrderDetail.getNeedle();

            // 获取proTaskDetail下属派工信息
            List<AssignTask> assignTasks = assignTaskMap.get(proTaskDetail.getId());

            Optional<NeedProduceDto> first = res.stream().filter(c -> needle.equals(c.getNeedle())).findFirst();
            if (first.isPresent()) {
                // 有值
                NeedProduceDto needProduceDto = first.get();
                needProduceDto.setTaskQty(needProduceDto.getTaskQty().add(BigDecimal.valueOf(proTaskDetail.getNumber())));

                if (assignTasks != null && !assignTasks.isEmpty()) {
                    needProduceDto.setFinishQty(
                            needProduceDto.getFinishQty()
                                    .add(assignTasks.stream()
                                            .map(AssignTask::getCompleteQty)
                                            .reduce(BigDecimal.ZERO, BigDecimal::add)));
                    needProduceDto.setNotFinishQty(needProduceDto.getTaskQty().subtract(needProduceDto.getFinishQty()));
                }
            }else {
                // 无值
                NeedProduceDto needProduceDto = NeedProduceDto.builder()
                        .needle(needle)
                        .taskQty(BigDecimal.valueOf(proTaskDetail.getNumber()))
                        .finishQty(BigDecimal.ZERO)
                        .notFinishQty(BigDecimal.valueOf(proTaskDetail.getNumber()))
                        .build();

                if (assignTasks != null && !assignTasks.isEmpty()) {
                    needProduceDto.setFinishQty(
                            assignTasks.stream()
                                    .map(AssignTask::getCompleteQty)
                                    .reduce(BigDecimal.ZERO, BigDecimal::add));
                    needProduceDto.setNotFinishQty(
                            needProduceDto.getTaskQty()
                                    .subtract(needProduceDto.getFinishQty()));
                }
                res.add(needProduceDto);
            }

        }
        return BizResult.success(res);
    }

    /**
     * 待生产明细
     * @param needle
     * @param proTaskCode
     * @return
     */
    @Override
    public BizResult<List<NeedProduceDetailDto>> needProduceDetail(String needle, String proTaskCode) {
        List<ProTask> proTaskList = proTaskMapper.selectList(new QueryWrapper<ProTask>().eq("IsDeleted", 0));
        Map<String, List<ProTaskDetail>> proTaskDetailMap = new HashMap<>();
        if (!proTaskList.isEmpty()) {
            List<ProTaskDetail> details = proTaskDetailMapper
                    .selectList(new QueryWrapper<ProTaskDetail>().eq("type", 0).eq("IsDeleted", 0));

            if (!details.isEmpty())
                proTaskDetailMap.putAll(details.stream().collect(Collectors.groupingBy(ProTaskDetail::getTaskId)));
        }

        // 生产单未完成并且是非委外的订单明细
        List<ProTaskDetail> proTaskDetails = new ArrayList<>();
        for (ProTask proTask : proTaskList) {
            List<ProTaskDetail> details = proTaskDetailMap.get(proTask.getId());
            if (details != null && !details.isEmpty())
                if (proTask.getIsFinish() == 0)
                    proTaskDetails.addAll(details);
        }

        Map<String, List<AssignTask>> assignTaskMap = new HashMap<>();
        Map<String, TradeOrderDetail> tradeOrderDetailMap = new HashMap<>();
        Map<String, ProTask> proTaskMap = new HashMap<>();
        if (!proTaskDetails.isEmpty()) {
            Set<String> tradeOrderDetailIds = proTaskDetails.stream().map(ProTaskDetail::getTradeOrderDetailId).collect(Collectors.toSet());
            if (!tradeOrderDetailIds.isEmpty()) {
                List<TradeOrderDetail> tradeOrderDetail = tradeOrderDetailMapper.selectBatchIds(tradeOrderDetailIds);
                if (!tradeOrderDetail.isEmpty())
                    tradeOrderDetailMap.putAll(tradeOrderDetail.stream().collect(Collectors.toMap(TradeOrderDetail::getId, c -> c)));
            }

            List<String> proTaskDetailIds = proTaskDetails.stream().map(ProTaskDetail::getId).collect(Collectors.toList());
            List<AssignTask> assignTasks = assignTaskService.list(new QueryWrapper<AssignTask>()
                    .in("task_detail_id", proTaskDetailIds));
            if (!assignTasks.isEmpty())
                assignTaskMap.putAll(assignTasks.stream().collect(Collectors.groupingBy(AssignTask::getTaskDetailId)));

            Set<String> proTaskIds = proTaskDetails.stream().map(ProTaskDetail::getTaskId).collect(Collectors.toSet());
            if (!proTaskIds.isEmpty())
                proTaskMap.putAll(proTaskMapper.selectBatchIds(proTaskIds)
                        .stream()
                        .collect(Collectors.toMap(ProTask::getId, c -> c)));
        }

        List<NeedProduceDetailDto> res = new ArrayList<>();
        for (ProTaskDetail proTaskDetail : proTaskDetails) {
            TradeOrderDetail tradeOrderDetail = tradeOrderDetailMap.get(proTaskDetail.getTradeOrderDetailId());
            if (tradeOrderDetail == null)
                continue;
            if (!needle.equals(tradeOrderDetail.getNeedle()))
                continue;

            Customer customers = customerMapper.selectById(tradeOrderDetail.getCustomerId());
            String customer = customers == null ? null : customers.getName();
            BigDecimal taskQty = BigDecimal.valueOf(proTaskDetail.getNumber());

            ProTask proTask = proTaskMap.get(proTaskDetail.getTaskId());
            List<AssignTask> assignTasks = assignTaskMap.get(proTaskDetail.getId());
            BigDecimal finishQty = BigDecimal.ZERO;
            if (assignTasks != null)
                finishQty = assignTasks.stream()
                        .map(AssignTask::getCompleteQty)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);

            res.add(NeedProduceDetailDto.builder()
                    .proTaskDetailId(proTaskDetail.getId())
                    .proTaskCode(proTask == null ? null :proTask.getCode())
                    .styleCode(tradeOrderDetail.getStyleCode())
                    .customer(customer)
                    .dyStyle(tradeOrderDetail.getDyStyle())
                    .colorName(tradeOrderDetail.getColorName())
                    .colorMain(tradeOrderDetail.getColorMain())
                    .needle(needle)
                    .orderHod(proTaskDetail.getOrderHod() == null ?
                            null :
                            DateUtil.formatDateToString(proTaskDetail.getOrderHod(), DateUtil.DATE_FORMAT_1))
                    .taskQty(taskQty)
                    .finishQty(finishQty)
                    .notFinishQty(taskQty.compareTo(finishQty) > 0 ?
                            taskQty.subtract(finishQty) : BigDecimal.ZERO)
                    .build());
        }

        // 过滤
        if (StringUtils.isNotBlank(proTaskCode))
            res = res.stream().filter(c -> c.getProTaskCode().contains(proTaskCode)).collect(Collectors.toList());

        return BizResult.success(res);
    }


}
